package com.yoyo.ad.confusion;

import android.content.Context;

import androidx.annotation.NonNull;

import com.bytedance.sdk.openadsdk.TTAdNative;
import com.yoyo.ad.bean.AdConfigList;
import com.yoyo.ad.bean.AdConfigListBean;
import com.yoyo.ad.bean.AdInterceptBean;
import com.yoyo.ad.bean.AdLocalConfig;
import com.yoyo.ad.bean.AdSourceConfigListBean;
import com.yoyo.ad.contract.AdContract;
import com.yoyo.ad.gen.AdConfigListBeanDao;
import com.yoyo.ad.gen.AdLocalConfigDao;
import com.yoyo.ad.main.IAdBannerListener;
import com.yoyo.ad.main.IAdFactory;
import com.yoyo.ad.main.IAdInteractionListener;
import com.yoyo.ad.main.IAdIpCount;
import com.yoyo.ad.main.IAdSource;
import com.yoyo.ad.main.IAdSource_;
import com.yoyo.ad.main.IAdView;
import com.yoyo.ad.main.IKey;
import com.yoyo.ad.presenter.AdPresenter;
import com.yoyo.ad.service.RequestService;
import com.yoyo.ad.utils.GreenDaoManager;
import com.yoyo.ad.utils.SystemUtil;
import com.yoyo.ad.utils.TimeUtils;

import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;

public class AdManage {

    public static final int EMPTY = 0;
    public static final int BAIDU = 1;
    public static final int TENCENT = 2;
    public static final int TOU_TIAO = 3;
    public static final int GDT = 4;
    public static final int YOYO = 5;
    public static final int YOYO_PLAT = 6;

    //1设备时间限制次数,2设备单日总次数限制次数,3ip,4总来源单次展示最少间隔时间,5总来源单日最多展示次数
    private static final int INTERCEPT_TIME = 1;
    private static final int INTERCEPT_COUNT = 2;
    private static final int INTERCEPT_IP = 3;
    private static final int INTERCEPT_TOTAL_TIME = 4;
    private static final int INTERCEPT_TOTAL_COUNT = 5;
    public static final int INTERCEPT_POSITION = 6;
    public static final int INTERCEPT_VERSION = 7;

    private static int AD_TYPE = BAIDU; //全局变量,表示当前在前台的activity数量
    private static int AD_SWITCH_INTERVAL = 3 * 60 * 1000;
    private static final long startTime = System.currentTimeMillis() / (1000 * 3600 * 24) * (1000 * 3600 * 24) - TimeZone.getDefault().getRawOffset();

    @NonNull
    public static IAdFactory newInstance(Context context, IAdView adView, TTAdNative ttAdBean) {
        return new AdFactory(context, adView, ttAdBean);
    }

    @NonNull
    public static IAdFactory newInstance(Context context, IAdBannerListener adView, TTAdNative ttAdBean) {
        return new AdFactory(context, adView, ttAdBean);
    }


    @NonNull
    public static IAdFactory newInstance(Context context, IAdInteractionListener adView, TTAdNative ttAdBean) {
        return new AdFactory(context, adView, ttAdBean);
    }

    public static boolean isBaiduAd() {
        return getAdType() == BAIDU;
    }

    public static boolean isTencentAd() {
        return getAdType() == TENCENT;
    }

    public static boolean isTouTiaoAd() {
        return getAdType() == TOU_TIAO;
    }

    static void getAdType(final Context context, final int position, final IAdSource iAdSource) {
        getAdType(context, position, iAdSource, null);
    }

    static void getAdType(final Context context, final int position, final IAdSource_ iAdSource) {
        getAdType(context, position, null, iAdSource);
    }

    static void getAdType(final Context context, final int position, final IAdSource iAdSource, final IAdSource_ iAdSource_) {
        GreenDaoManager.getInstance().getDaoSession()
                .getAdConfigListBeanDao()
                .queryBuilder()
                .where(AdConfigListBeanDao.Properties.AdPositionConfigId.eq(position))
                .orderAsc(AdConfigListBeanDao.Properties.Sort)
                .rx()
                .list()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<AdConfigListBean>>() {
                               @Override
                               public void call(final List<AdConfigListBean> res) {
                                   if (res.size() < 1) {
                                       if (iAdSource != null)
                                           iAdSource.adSource(EMPTY, 0L, "", false);
                                       if (iAdSource_ != null) {
                                           List<AdConfigList> list = new ArrayList<>();
                                           list.add(new AdConfigList(EMPTY, 0L, ""));
                                           iAdSource_.adSource(list, false);
                                       }
                                       return;
                                   }
                                   boolean b = false;
                                   for (int i = 0; i < res.size(); i++) {
                                       if (res.get(i).getIpShowMaxCount() > 0) {
                                           b = true;
                                           break;
                                       }
                                   }
                                   if (b) {
                                       String ids = "";
                                       for (AdConfigListBean ad : res) {
                                           ids = ids.concat(String.valueOf(ad.getAdId())).concat(",");
                                       }
                                       if (!ids.isEmpty()) {
                                           ids = ids.substring(0, ids.length() - 1);
                                       }
                                       if (!AdLocalSourceRecord.canRequestIpData(context, res.get(0).getIpShowSpaceSecond())) {
                                           if (iAdSource != null)
                                               getAdSource(context, position, res, null, iAdSource, "");
                                           if (iAdSource_ != null)
                                               getAdSource(context, position, res, null, iAdSource_, "");
                                           return;
                                       }
                                       new AdPresenter(context, new AdContract.View() {
                                           @Override
                                           public void onAdSuccess() {

                                           }

                                           @Override
                                           public void onAdFail(String err) {
                                               if (iAdSource != null)
                                                   getAdSource(context, position, res, null, iAdSource, "");
                                               if (iAdSource_ != null)
                                                   getAdSource(context, position, res, null, iAdSource_, "");

                                           }
                                       }).qryCIpShowCount(ids, new IAdIpCount() {
                                           @Override
                                           public void adIpCounts(String[] adIds, JSONObject counts) {
                                               AdLocalSourceRecord.setRequestIpDataTime(context);
                                               if (iAdSource != null)
                                                   getAdSource(context, position, res, counts, iAdSource, adIds);
                                               if (iAdSource_ != null)
                                                   getAdSource(context, position, res, counts, iAdSource_, adIds);
                                           }
                                       });
                                   } else {
                                       if (iAdSource != null)
                                           getAdSource(context, position, res, null, iAdSource, "");
                                       if (iAdSource_ != null)
                                           getAdSource(context, position, res, null, iAdSource_, "");
                                   }
                               }
                           },
                        new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {
                                if (iAdSource != null)
                                    iAdSource.adSource(EMPTY, 0L, "", false);
                                if (iAdSource_ != null) {
                                    List<AdConfigList> list = new ArrayList<>();
                                    list.add(new AdConfigList(EMPTY, 0L, ""));
                                    iAdSource_.adSource(list, false);
                                }
                            }
                        });
    }


    /**
     * 获取要显示的广告来源
     *
     * @param list      广告配置列表
     * @param adIps     当前ip数量列表
     * @param iAdSource 返回监听
     * @param adIds     广告id列表
     */
    private static void getAdSource(final Context context, int position, List<AdConfigListBean> list, JSONObject adIps, IAdSource iAdSource, String... adIds) {
        getAdSource(context, position, list, adIps, iAdSource, null, adIds);
    }

    private static void getAdSource(final Context context, int position, List<AdConfigListBean> list, JSONObject adIps, IAdSource_ iAdSource, String... adIds) {
        getAdSource(context, position, list, adIps, null, iAdSource, adIds);
    }

    private static void getAdSource(final Context context, int position, List<AdConfigListBean> list, JSONObject adIps, IAdSource iAdSource, IAdSource_ iAdSource_, String... adIds) {
        long time = System.currentTimeMillis();
        final String date = TimeUtils.getDate(time);
        //来源配置列表
        List<AdSourceConfigListBean> adSourceConfigListBeans = GreenDaoManager.getInstance().getDaoSession()
                .getAdSourceConfigListBeanDao().loadAll();
        //清空缓存数据
        if (!AdLocalSourceRecord.isDeleteData(context, date)) {
            GreenDaoManager.getInstance().getDaoSession().getAdLocalConfigDao().queryBuilder()
                    .where(AdLocalConfigDao.Properties.CreateTime.notEq(date)).rx().list()
                    .subscribeOn(rx.schedulers.Schedulers.io()).subscribe(new Action1<List<AdLocalConfig>>() {
                @Override
                public void call(List<AdLocalConfig> adLocalConfigs) {
                    if (adLocalConfigs.size() > 0) {
                        GreenDaoManager.getInstance().getDaoSession().getAdLocalConfigDao().rx().deleteInTx(adLocalConfigs)
                                .subscribeOn(Schedulers.io()).subscribe(new Action1<Void>() {
                            @Override
                            public void call(Void vVoid) {
                                AdLocalSourceRecord.setDeleteData(context, date);
                            }
                        });
                    } else {
                        AdLocalSourceRecord.setDeleteData(context, date);
                    }
                }
            });
        }
        //本地记录信息
        List<AdLocalConfig> adLocalConfigs = GreenDaoManager.getInstance().getDaoSession().getAdLocalConfigDao()
                .queryBuilder().where(AdLocalConfigDao.Properties.AdPositionId.eq(list.get(0).getAdPositionConfigId())
                        , AdLocalConfigDao.Properties.CreateTime.eq(date)).list();

        int size = adLocalConfigs.size();
        //判断是否有ip限制的本地记录
        boolean isIpReport = adIds.length > 1;
        if (isIpReport) {
            a:
            for (String adId : adIds) {
                //判断当前广告id是否有本地记录，有则更新ip限制数量，没有则添加
                for (int i = 0; i < size; i++) {
                    if (adId.equals(String.valueOf(adLocalConfigs.get(i).getAdId()))) {
                        adLocalConfigs.get(i).setIpCount(adIps.optInt(adId));
                        continue a;
                    }
                }
                adLocalConfigs.add(new AdLocalConfig(null, Long.parseLong(adId), list.get(0).getAdPositionConfigId(),
                        0L, date, 0, adIps.optInt(adId)));
            }
            //将ip数量添加到本地库
            GreenDaoManager.getInstance().getDaoSession().getAdLocalConfigDao().rx().insertOrReplaceInTx(adLocalConfigs).subscribeOn(rx.schedulers.Schedulers.io()).subscribe();
        }

        Map<String, AdLocalConfig> localList = getMap(adLocalConfigs);
        Map<String, AdSourceConfigListBean> sourceList = getMap(adSourceConfigListBeans);

        int adSource = EMPTY;
        String adPlaceId = "";
        long adId = 0L;
        boolean isMUp = SystemUtil.isVersionMUp();
        List<AdInterceptBean> interceptList = new ArrayList<>();
        List<AdConfigList> resList = new ArrayList<>();
        //限制条件判断
        //因为所有条件都要判断，所以列表按优先级正序排列，直接覆盖未被限制得展示来源即可
        int size1 = list.size();
        for (int i = 0; i < size1; i++) {
            boolean isIntercept = false;
            AdConfigListBean adConfigListBean = list.get(i);
            if (adConfigListBean.getAdSourceId() == TENCENT && isMUp) {
                //7.0以上含系统签名应用拦截广点通
                interceptList.add(new AdInterceptBean(adConfigListBean.getAdId(), INTERCEPT_VERSION, date));
                continue;
            }
            AdLocalConfig adLocalConfig = localList.get(String.valueOf(adConfigListBean.getAdId()));
            AdSourceConfigListBean adSourceConfig = sourceList.get(String.valueOf(adConfigListBean.getAdSourceId()));
            if (adLocalConfig == null) {
                //来源判断
                if (adSourceConfig == null) {
                    adSource = adConfigListBean.getAdSourceId();
                    adPlaceId = adConfigListBean.getAdCode();
                    adId = adConfigListBean.getAdId();
                    resList.add(new AdConfigList(adSource, adId, adPlaceId, adConfigListBean.getSort()));
                    continue;
                } else {
                    if (adSourceConfig.getMinSpaceCount() <= AdLocalSourceRecord.getLocalSourceCount(context, adConfigListBean.getAdSourceId())) {
                        interceptList.add(new AdInterceptBean(adConfigListBean.getAdId(), INTERCEPT_TOTAL_COUNT, date));
                        isIntercept = true;
                    }
                    long localSourceTime = AdLocalSourceRecord.getLocalSourceTime(context, adConfigListBean.getAdSourceId());
                    if (!(localSourceTime <= 0L || (adSourceConfig.getMinSpaceSecond() * 1000 < time - localSourceTime))) {
                        interceptList.add(new AdInterceptBean(adConfigListBean.getAdId(), INTERCEPT_TOTAL_TIME, date));
                        isIntercept = true;
                    }
                }
                if (!isIntercept) {
                    adSource = adConfigListBean.getAdSourceId();
                    adPlaceId = adConfigListBean.getAdCode();
                    adId = adConfigListBean.getAdId();
                    resList.add(new AdConfigList(adSource, adId, adPlaceId, adConfigListBean.getSort()));
                }
                continue;
            }
            if (adConfigListBean.getIpShowMaxCount() > 0 && adConfigListBean.getIpShowMaxCount() <= adLocalConfig.getIpCount()) {
                interceptList.add(new AdInterceptBean(adConfigListBean.getAdId(), INTERCEPT_IP, date));
                isIntercept = true;
            }
            if (adConfigListBean.getShowMaxCount() <= adLocalConfig.getShowCount()) {
                interceptList.add(new AdInterceptBean(adConfigListBean.getAdId(), INTERCEPT_COUNT, date));
                isIntercept = true;
            }

            if (!(adLocalConfig.getRecentShowTime() <= 0L || (adConfigListBean.getShowSpaceSecond() * 1000 < time - adLocalConfig.getRecentShowTime()))) {
                interceptList.add(new AdInterceptBean(adConfigListBean.getAdId(), INTERCEPT_TIME, date));
                isIntercept = true;
            }

            //来源判断
            if (adSourceConfig == null) {
                if (!isIntercept) {
                    adSource = adConfigListBean.getAdSourceId();
                    adPlaceId = adConfigListBean.getAdCode();
                    adId = adConfigListBean.getAdId();
                    resList.add(new AdConfigList(adSource, adId, adPlaceId, adConfigListBean.getSort()));
                }
                continue;
            }
            if (adSourceConfig.getMinSpaceCount() <= AdLocalSourceRecord.getLocalSourceCount(context, adConfigListBean.getAdSourceId())) {
                interceptList.add(new AdInterceptBean(adConfigListBean.getAdId(), INTERCEPT_TOTAL_COUNT, date));
                isIntercept = true;
            }
            long localSourceTime = AdLocalSourceRecord.getLocalSourceTime(context, adConfigListBean.getAdSourceId());
            if (!(localSourceTime <= 0L || (adSourceConfig.getMinSpaceSecond() * 1000 < time - localSourceTime))) {
                interceptList.add(new AdInterceptBean(adConfigListBean.getAdId(), INTERCEPT_TOTAL_TIME, date));
                isIntercept = true;
            }
            if (!isIntercept) {
                adSource = adConfigListBean.getAdSourceId();
                adPlaceId = adConfigListBean.getAdCode();
                adId = adConfigListBean.getAdId();
                resList.add(new AdConfigList(adSource, adId, adPlaceId, adConfigListBean.getSort()));
            }
        }
        if (iAdSource != null) {
            iAdSource.adSource(adSource, adId, adPlaceId, isIpReport);
        }
        if (iAdSource_ != null) {
            iAdSource_.adSource(resList, isIpReport);
        }
        if (adSource == EMPTY) {
            interceptList.add(new AdInterceptBean(position, date));
        }

        //写入广告限制
        GreenDaoManager.getInstance().getDaoSession().getAdInterceptBeanDao().rx()
                .insertOrReplaceInTx(interceptList)
                .subscribeOn(rx.schedulers.Schedulers.io()).subscribe();

        RequestService.newInstance(context, RequestService.FLAG_CONFINED_REPORT);
    }


    /**
     * 广告展示成功后记录广告显示数据
     *
     * @param sourceId     广告来源
     * @param adId         广告id
     * @param adPositionId 广告位id
     * @param isIpReport   是否需要进行ip上报记录
     */
    public static void showAdSuccess(Context context, int sourceId, final long adId, final int adPositionId, boolean isIpReport) {
        if (sourceId == EMPTY || adId == 0L) {
            return;
        }
        AdLocalSourceRecord.setLocalSource(context, sourceId);
        GreenDaoManager.getInstance().getDaoSession().getAdLocalConfigDao().queryBuilder()
                .where(AdLocalConfigDao.Properties.AdId.eq(adId)).rx()
                .list()
                .subscribeOn(rx.schedulers.Schedulers.io())
                .subscribe(new Action1<List<AdLocalConfig>>() {
                               @Override
                               public void call(List<AdLocalConfig> list) {
                                   AdLocalConfig adLocalConfig = list.size() > 0 ? list.get(0) : new AdLocalConfig(adId, adPositionId);
                                   adLocalConfig.setRecentShowTime(System.currentTimeMillis());
                                   adLocalConfig.setShowCount(adLocalConfig.getShowCount() + 1);
                                   GreenDaoManager.getInstance().getDaoSession().getAdLocalConfigDao()
                                           .rx().insertOrReplace(adLocalConfig)
                                           .subscribeOn(Schedulers.io()).subscribe();
                               }
                           }
                );
        if (isIpReport) {
            new AdPresenter(context, null).addCIpShowCount(adId);
        }
    }

    /**
     * list转map，便于获取对应的对象，对象需实现{@link IKey}接口
     */
    private static <T extends IKey> Map<String, T> getMap(List<T> adLocalConfigs) {
        HashMap<String, T> map = new HashMap<>();
        for (T t : adLocalConfigs) {
            map.put(t.getKey(), t);
        }
        return map;
    }

    private static int getAdType() {
        long l = System.currentTimeMillis();
        int interval = (int) (((l - startTime) / AD_SWITCH_INTERVAL) % 3);
        if ((interval == 0 && AD_TYPE != TENCENT) || (interval == 1 && AD_TYPE != BAIDU) || (interval == 2 && AD_TYPE != TOU_TIAO)) {
            switch (interval) {
                case 0:
                    AD_TYPE = TENCENT;
                    break;
                case 1:
                    AD_TYPE = BAIDU;
                    break;
                case 2:
                    AD_TYPE = TOU_TIAO;
                    break;
            }
        }
        return AD_TYPE;
    }

    public static boolean hasChange() {
        int adType = AD_TYPE;
        return adType != getAdType();
    }

    public static void setAdSwitchInterval(int adSwitchInterval) {
        if (adSwitchInterval > 0)
            AD_SWITCH_INTERVAL = adSwitchInterval * 60 * 1000;
    }


}
